package base

import (
	"fmt"
	"gitee.com/ymofen/gobase"
	"gitee.com/ymofen/gobase/factory"
	"io"
)

type DataConverter interface {
	UpdateConf(conf gobase.StrMap)
	InputBuf(buf []byte) (newBuf []byte, err error)
}

type ConvDecoder interface {
	InputBuf(buf []byte) ([]any, error)
	UpdateConf(conf gobase.StrMap)
}

type ConvEncoder interface {
	Input(val any) ([]byte, error)
	UpdateConf(conf gobase.StrMap)
}

var (
	ErrUnKownType = fmt.Errorf("unkown type")
)

func TryClose(v interface{}) (ok bool, err error) {
	if intf, ok0 := v.(io.Closer); ok0 {
		err = intf.Close()
		ok = true
		return
	} else {
		return false, gobase.ErrUnsupported
	}
}

func TryGetStatus(v interface{}, args ...interface{}) string {
	if intf, ok0 := v.(gobase.StatuGetter); ok0 {
		return intf.GetStatus(args...)
	} else {
		return ""
	}
}

func CreateDataConverterEx(confMap gobase.StrMap) (rval DataConverter, err error) {
	ctype := confMap.StringByName("type", "")
	if len(ctype) == 0 {
		return nil, ErrUnKownType
	} else {
		v0, err := factory.CreateInstance(fmt.Sprintf("converter.%s", ctype))
		if err != nil {
			return nil, err
		}
		if intf, ok := v0.(DataConverter); ok {
			intf.UpdateConf(confMap)
			return intf, nil
		} else {
			TryClose(v0)
			return nil, gobase.ErrUnsupported
		}
	}
}

func CreateConverterEncoder(confMap gobase.StrMap) (rval ConvEncoder, err error) {
	ctype := confMap.StringByName("type", "")
	if len(ctype) == 0 {
		return nil, ErrUnKownType
	} else {
		v0, err := factory.CreateInstance(fmt.Sprintf("converter.encoder.%s", ctype))
		if err != nil {
			return nil, err
		}
		if intf, ok := v0.(ConvEncoder); ok {
			intf.UpdateConf(confMap)
			return intf, nil
		} else {
			TryClose(v0)
			return nil, gobase.ErrUnsupported
		}
	}
}

func CreateConverterDecoder(confMap gobase.StrMap) (rval ConvDecoder, err error) {
	ctype := confMap.StringByName("type", "")
	if len(ctype) == 0 {
		return nil, ErrUnKownType
	} else {
		v0, err := factory.CreateInstance(fmt.Sprintf("converter.decoder.%s", ctype))
		if err != nil {
			return nil, err
		}
		if intf, ok := v0.(ConvDecoder); ok {
			intf.UpdateConf(confMap)
			return intf, nil
		} else {
			TryClose(v0)
			return nil, gobase.ErrUnsupported
		}
	}
}

func CreateDataConverter(s string) (rval DataConverter, err error) {
	confMap := gobase.NewStrMap()
	confMap.URLFormDecode(s)
	ctype := confMap.StringByName("type", "")
	if len(ctype) == 0 {
		return nil, ErrUnKownType
	} else {
		v0, err := factory.CreateInstance(fmt.Sprintf("converter.%s", ctype))
		if err != nil {
			return nil, err
		}
		if intf, ok := v0.(DataConverter); ok {
			intf.UpdateConf(confMap)
			return intf, nil
		} else {
			TryClose(v0)
			return nil, gobase.ErrUnsupported
		}
	}
}
